package com.jarcheng.user.service.impl;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jarcheng.common.common.Result;
import com.jarcheng.common.common.ResultCode;
import com.jarcheng.common.utils.MultipartFileToFile;
import com.jarcheng.mbg.dao.UserDao;
import com.jarcheng.mbg.entity.User;
import com.jarcheng.shiro.config.shiro.JWTToken;
import com.jarcheng.common.utils.JWTUtils;
import com.jarcheng.shiro.utils.MD5Utils;
import com.jarcheng.user.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Autowired
    UserDao userDao;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Value("${redis.key.prefix.authCode}")
    private String REDIS_KEY_PREFIX_AUTH_CODE;
    @Value("${redis.key.expire.authCode}")
    private Long AUTH_CODE_EXPIRE_SECONDS;

    @Override
//    @Cacheable(value = "user", key = "#uuid")
    public Result getUserInfo(String uuid) {
        log.info(uuid);
        if (uuid.equals("")) {
            User user = (User) SecurityUtils.getSubject().getPrincipal();
            user.setPassword("");
            return Result.SUCCESS(user);
        } else {
            return Result.SUCCESS(userDao.selectByUUID(uuid));
        }
    }

    @Override
    public User getUserInfoByID(Integer id) {
        return userDao.selectByPrimaryKey(id);
    }


    @Override
    public Result login(User user) {
        JSONObject result = new JSONObject();
        Subject subject = SecurityUtils.getSubject();
        String target = MD5Utils.md5Encryption(user.getPassword(), user.getName());
        String token = JWTUtils.sign(user.getName(), target);
//        String token = JwtTokenUtil.createJWT(user.getPassword(), user.getName(), audience);
        try {
            subject.login(new JWTToken(token));
            // 登录成功 封装用户信息到token
            result.put("token", token);
            return Result.SUCCESS(result);
        } catch (UnknownAccountException e) {
            return new Result(ResultCode.USER_NOT_EXIST);
        } catch (IncorrectCredentialsException e) {
            return new Result(ResultCode.USER_LOGIN_ERROR);
        }
    }

    @Override
    public Result signUp(User user) {
        if (user.getCode().equals("") || user.getCode() == null) return new Result(ResultCode.PARAM_IS_BLANK);

        Result verifyAuthCode = verifyAuthCode(user.getTelephone(), user.getCode());
        if (verifyAuthCode.getMessage().equals("验证码不正确")) {
            return verifyAuthCode;
        }
        JSONObject result = new JSONObject();
        String userId = UUID.randomUUID().toString();
        user.setUuid(userId);
        if (user.getName() != null && user.getPassword() != null) {
            User queryUser = userDao.selectByName(user.getName());
            if (queryUser == null) {
                userDao.insertSelective(user);
                String target = MD5Utils.md5Encryption(user.getPassword(), user.getName());
                String token = JWTUtils.sign(user.getName(), target);
                result.put("token", token);
                Result.SUCCESS(result);
                return Result.SUCCESS(result);
            }
        } else {
            return new Result(ResultCode.PARAM_TYPE_BIND_ERROR);
        }
        return new Result(ResultCode.USER_HAS_EXISTED);
    }

    @Override
    @Cacheable(value = "allUserCache", unless = "#result.size()==0")
    public Result listUsers(int start, int size) {
        PageInfo<User> page = null;
        PageHelper.startPage(start, size);
        List<User> users = userDao.selectAllUser();
        for (User user : users) {
            user.setPassword("");
        }
        page = new PageInfo<>(users, 5);
        return Result.SUCCESS(page);
    }


    @Override
    public Result deleteUser(String uuid) {
        return Result.SUCCESS(userDao.deleteByUUID(uuid));
    }


    @CacheEvict(value = "user", key = "#user.uuid")
    @Override
    public Result updateInfo(User user) {
        return Result.SUCCESS(userDao.updateByUUIDSelective(user));
    }

    @Override
    public Result getAuthCode(String phoneNumber) {
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < 6; i++) {
            sb.append(random.nextInt(10));
        }

        stringRedisTemplate.opsForValue().set(REDIS_KEY_PREFIX_AUTH_CODE + phoneNumber, sb.toString());
        stringRedisTemplate.expire(REDIS_KEY_PREFIX_AUTH_CODE + phoneNumber, AUTH_CODE_EXPIRE_SECONDS, TimeUnit.SECONDS);
        return Result.SUCCESS(sb.toString() + "获取验证码成功");
    }

    @Override
    public Result verifyAuthCode(String phoneNumber, String code) {
        if (StringUtils.isEmpty(code)) {
            return Result.FAIL("请输入验证码");
        }
        String realAuthCode = stringRedisTemplate.opsForValue().get(REDIS_KEY_PREFIX_AUTH_CODE + phoneNumber);
        boolean result = code.equals(realAuthCode);
        if (result) {
            return Result.SUCCESS("验证码校验成功");
        } else {
            return Result.FAIL("验证码不正确");
        }
    }

    @Override
    public Result faceLogin(MultipartFile userFace, String name) {
        HashMap<String, Object> param = new HashMap<>();
        try {
            param.put("file", MultipartFileToFile.multipartFileToFile(userFace));
        } catch (Exception e) {
            return Result.FAIL();
        }
        String result = HttpUtil.post("http://localhost:5000/upload", param);
        JSONObject jsonObject = JSONObject.parseObject(result);
        String realName = (String) jsonObject.get("name");
        log.info(realName);
        log.info(name);
        if (realName.equals(name.trim())) return login(userDao.selectByRealName(realName));
        return Result.FAIL("照片与姓名不符");
    }
}
